/*
 *  de.karnik.helper - Library for basic helper functions
 *  Copyright (C) 2007-2008 Markus Karnik
 *
 *  This program is free software; you can redistribute it and/or modify it 
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 3 of the License, 
 *  or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along 
 *  with this program; if not, see <http://www.gnu.org/licenses/>.
 *  
 */

package de.karnik.helper;

import org.apache.commons.codec.binary.Base64;
import java.util.Random;

/**
 * Useful methods to handle, convert or create strings.
 * 
 * @author Markus Karnik - markus.karnik@my-design.org
 * @version 1.0
 * @since 1.0
 */
public class StringFunctions {

	private static int uniqueStringCounter = 0;
	
	/**
	 * Returns a unique string.
	 * 
	 * @return The unique string.
	 */
	public static String getUniqueString() {
		
		StringBuffer sb = new StringBuffer();
		Random random = new Random( System.nanoTime() );

		boolean temp1 = random.nextBoolean();
		double temp2 = 0.0d;
		
		// create a random double or a random gaussian
		if( temp1 ) {
			temp2 = random.nextDouble() * 1000;
		} else {
			temp2 = random.nextGaussian() * 10000;
		}
		
		// append unique md5 string based up on the random value an the counter
		sb.append( random.toString() ).append( temp1 ).append( temp2 ).append( StringFunctions.uniqueStringCounter );
		
		// append counter to be sure to get a unique id
		sb = new StringBuffer( HashFunctions.md5( sb.toString() ) );
		sb.append( "-" ).append( StringFunctions.uniqueStringCounter );
		
		// increment counter to be sure to get a unique id next time
		StringFunctions.uniqueStringCounter++;
		
		return sb.toString();
	}
	
	/**
	 * Creates and returns a string based on the given parameters. 
	 * The counter is converted to a hex string and filled with zero until the given length is reached.
	 * 
	 * @param base The string to indicate the usage.
	 * @param counter The counter to indicate the current value.
	 * @param length The maximum length of the hex value.
	 * @return A String based on the given parameters. 
	 */
	public static String getIncrementalHexString( String base, int counter, int length ) {
		StringBuffer sb = new StringBuffer( base );
		sb.append( StringFunctions.fillWithCharacter( Integer.toHexString( counter ), '0', length ) );
		
		return sb.toString();
	}
	
	/**
	 * Decodes and returns the given Base64 encoded string.
	 * 
	 * @param string Base64 encoded string.
	 * @return The decoded string.
	 */
	public static String decodeBase64( String string ) {
		byte[] temp = Base64.decodeBase64( string.getBytes() );
		return new String ( temp );
	}
	
	/**
	 * Decodes and returns the given Base64 encoded byte[].
	 * 
	 * @param data Base64 encoded byte[].
	 * @return The decoded byte[].
	 */
	public static byte[] decodeBase64( byte[] data ) {
		byte[] temp = Base64.decodeBase64( data );
		return temp;
	}

	/**
	 * Encodes and returns the given string to Base64.
	 * 
	 * @param string The string to encode.
	 * @return The Base64 encoded string.
	 */
	public static String encodeBase64( String string ) {
		byte[] temp = Base64.encodeBase64( string.getBytes() );
		return new String ( temp );
	}
	

	/**
	 * Encodes and returns the given byte[] to Base64.
	 * 
	 * @param data The byte[] to encode.
	 * @return The Base64 encoded byte[].
	 */
	public static byte[] encodeBase64( byte[] data ) {
		byte[] temp = Base64.encodeBase64( data );
		return temp;
	}
	
	/**
	 * Fills up a string with characters. 
	 * 
	 * @param string The string to fill.
	 * @param character The character to fill up the string.
	 * @param length The maximum length of the target string.
	 * @return The filled up string.
	 */
	public static String fillWithCharacter( String string, char character, int length ) {
		StringBuffer sb = new StringBuffer();
		
		for( int i = 0; i < ( length - string.length() ); i++ )
			sb.append( character );
		
		return sb.append( string ).toString();
	}
	
	/**
	 * Removes the quotes from the given string.
	 *  
	 * @param string A string with quotes.
	 * @return The given string without quotes.
	 */
	public static String removeQuotes( String string ) {
		return string.substring( string.indexOf( "\"" ) + 1, string.lastIndexOf("\"" ) );
	}
	
	/**
	* Convenience method to convert a byte array to a hex string.
	*
	* @param data the byte[] to convert
	* @return String the converted byte[]
	*/
	public static String bytesToHex( byte[] data ) {
		StringBuffer buf = new StringBuffer();
	
		for ( int i = 0; i < data.length; i++ )
			buf./*append( " 0x" ).*/append( byteToHex( data[ i ] ) );
		return buf.toString();
	}
	
	/**
	* Convenience method to convert a byte to a hex string.
	*
	* @param data the byte to convert
	* @return String the converted byte
	*/
	public static String byteToHex( byte data ) {
		StringBuffer buf = new StringBuffer();
		buf.append( toHexChar( ( data>>>4 ) & 0x0F ) );
		buf.append( toHexChar( data & 0x0F ) );
		return buf.toString();
	}

	/**
	* Convenience method to convert an int to a hex char.
	*
	* @param i the int to convert
	* @return char the converted char
	*/
	public static char toHexChar( int i ) {
		if ( ( 0 <= i ) && ( i <= 9 ) )
			return ( char )( '0' + i );
		else
			return ( char )( 'a' + ( i-10 ) );
	}
	
	/**
	 * Converts and returns the correct string value for the given byte array.
	 * 
	 * @param bytes The byte array to convert.
	 * @return The correct string value for the given byte array.
	 */
	public static String toHexString( byte[] bytes ) { 
		char[] ret = new char[ bytes.length * 2 ];
			for ( int i = 0, j = 0; i < bytes.length; i++ ) {
				int c =( int ) bytes[ i ];
		        if ( c < 0 ) {
		            c += 0x100;
		        }
		        ret[ j++ ] = Character.forDigit( c / 0x10, 0x10 );
		        ret[ j++ ] = Character.forDigit( c % 0x10, 0x10 );
			}
			
		return new String( ret );
	}
	
	/**
	 * Converts the given byte to the correct string value.
	 * 
	 * @param b The byte to convert.
	 * @return The byte converted to the correct string value.
	 */
	public static String toHexString( byte b ) {
	         int value = (b & 0x7F) + (b < 0 ? 128 : 0);
	      
	          String ret = (value < 16 ? "0" : "");
	          ret += Integer.toHexString(value).toUpperCase();
	      
	      return ret;
	} 
}
